home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / lin_alg.lha / lin_alg / determinant.cc < prev    next >
C/C++ Source or Header  |  1993-08-08  |  5KB  |  198 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *            Linear Algebra Package
  6.  *
  7.  *        Compute the determinant of a general square matrix
  8.  *
  9.  * Synopsis
  10.  *    Matrix A;
  11.  *    double A.determinant();
  12.  * The matrix is assumed to be square. It is kept preserved.
  13.  *
  14.  * Method
  15.  *    Gauss-Jordan transformations of the matrix
  16.  *    Matrix elements are arranged in columns. But it doesn't really
  17.  *    matter since the determinant remains invariant under the
  18.  *    matrix transposition. Therefore, it makes sence to eliminate rows
  19.  *    rather than columnss in the Gauss-Jordan transformations.
  20.  *    The matrix is copied to a special object of type MatrixPivoting,
  21.  *    where all Gauss-Jordan eliminations with full pivoting are to
  22.  *    take place.
  23.  *
  24.  ************************************************************************
  25.  */
  26.  
  27. #include "LinAlg.h"
  28. #include <math.h>
  29.  
  30. #pragma implementation
  31.  
  32. /*
  33.  *------------------------------------------------------------------------
  34.  *            Class MatrixPivoting
  35.  *
  36.  * It is a descendant from the Matrix which keeps some information
  37.  * that makes pivoting easy. 
  38.  */
  39.  
  40. class MatrixPivoting
  41.   : public Matrix
  42. {
  43.   short * row_pivoted;            // row_pivoted[i] = 1 if the i-th
  44.                     // row has been pivoted. Note,
  45.                     // pivoted columns are marked
  46.                     // by putting index[j] to zero.
  47.  
  48.                 // Information about the pivot that was
  49.                 // just picked up
  50.   double pivot_value;            // Value of the pivoting element
  51.   short pivot_row;            // Row and column for the pivot
  52.   short pivot_col;            // just found
  53.   short pivot_parity;            // +1/-1, reflects the parity
  54.  
  55.   void pick_up_pivot(void);        // Pick up a pivot from the
  56.                     // not-pivoted rows and cols
  57.  
  58. public:
  59.   MatrixPivoting(const Matrix& m);    // Construct an object 
  60.                     // for a given matrix
  61.   ~MatrixPivoting(void);
  62.  
  63.   double pivoting_and_elimination(void);// Perform the pivoting, return
  64.                     // the pivot value times (-1)^(pi+pj)
  65.                     // (pi,pj - pivot el row & col)
  66. };
  67.  
  68.  
  69. /*
  70.  *------------------------------------------------------------------------
  71.  *        Constructing and decomissioning MatrixPivoting
  72.  */
  73.  
  74. MatrixPivoting::MatrixPivoting(const Matrix& m)
  75.   : Matrix(m.q_row_lwb(),m.q_row_upb(),m.q_col_lwb(),m.q_col_upb())
  76. {
  77.   m.is_valid();
  78.   memcpy(elements,m.elements,nelems*sizeof(REAL));
  79.   assert( (row_pivoted = calloc(nrows,sizeof(row_pivoted[0]))) != 0 );
  80. }
  81.  
  82. MatrixPivoting::~MatrixPivoting(void)
  83. {
  84.   is_valid();
  85.   assert( row_pivoted != 0 );
  86.   delete row_pivoted;
  87. }
  88.  
  89. /*
  90.  *------------------------------------------------------------------------
  91.  *                Pivoting itself
  92.  */
  93.  
  94.             // Pick up a pivot, the element with the largest
  95.             // abs value from the yet not-pivoted rows and cols
  96. void MatrixPivoting::pick_up_pivot(void)
  97. {
  98.   register int i,j;
  99.   register int si,sj;            // No. of already pivoted rows & cols
  100.   register REAL max_elem = -1;        // Abs value of the largest element
  101.   register REAL * mp;
  102.  
  103.   for(j=0,sj=0; j<ncols; j++)        // Picking up a not-pivoted column
  104.     if(index[j] == 0)
  105.       sj++;                // Skip already pivoted columns
  106.     else
  107.       for(i=0,si=0,mp=index[j]; i<nrows; i++)
  108.     if(row_pivoted[i])
  109.       mp++, si++;            // Skip elems in already pivoted rows
  110.     else
  111.     {
  112.       register REAL v = *mp++;
  113.       if( fabs(v) > max_elem )
  114.       {
  115.         max_elem = fabs(v);
  116.         pivot_value = v;
  117.         pivot_col = j;
  118.         pivot_row = i;
  119.         pivot_parity = i+j-si-sj;    // No. of transpositions for the pivot
  120.       }
  121.     }
  122.  
  123.   assure( max_elem >= 0, 
  124.      "All the rows and columns have been already pivoted and eliminated");
  125.   pivot_parity = (pivot_parity & 1 ? -1 : 1);    // (-1)^pivot_parity
  126. }
  127.  
  128.             // Perform pivoting and gaussian elemination,
  129.             // return the pivot value times pivot_parity
  130.             // The procedure places zeros to the pivot_row of
  131.             // all not yet pivoted columns
  132.             // A[i,j] -= A[i,pivot_col]/pivot*A[pivot_row,j]
  133. double MatrixPivoting::pivoting_and_elimination(void)
  134. {
  135.   is_valid();
  136.  
  137.   pick_up_pivot();
  138.   if( pivot_value == 0 )
  139.     return 0;
  140.  
  141.   REAL * pvc = index[pivot_col];        // Pivoted column ptr
  142.   assert( pvc != 0 );
  143.   register REAL * wp;                // Work pointer
  144.   register int i,j;
  145.  
  146.   index[pivot_col] = 0;            // Mark pivot_row & pivot_col
  147.   row_pivoted[pivot_row] = 1;        // as being pivoted
  148.  
  149.   for(i=0,wp=pvc; i<nrows; i++)        // Divide the pivoted column by pivot
  150.     if(row_pivoted[i])
  151.       wp++;                // Skip already pivoted rows
  152.     else
  153.       *wp++ /= pivot_value;
  154.  
  155.   for(j=0; j<ncols; j++)        // Eliminate all the elements from
  156.     if(index[j] != 0)            // the pivot_row in all not pivoted
  157.     {                    // columns
  158.       register REAL * mp = index[j];    // mp = A[i,j]
  159.       wp = pvc;                // wp = A[i,pivot_col]/pivot_value
  160.       register double fac = mp[pivot_row]; // fac = A[pivot_row,j]
  161.       for(i=0; i<nrows; i++)
  162.     if(row_pivoted[i])
  163.       mp++,wp++;            // Skip pivoted rows
  164.         else
  165.       *mp++ -= *wp++ * fac;
  166.     }
  167.  
  168.   return pivot_value * pivot_parity;
  169. }
  170.  
  171.  
  172. /*
  173.  *------------------------------------------------------------------------
  174.  *                Root module
  175.  */
  176.  
  177. double Matrix::determinant(void) const
  178. {
  179.   is_valid();
  180.  
  181.   if( nrows != ncols )
  182.     info(), _error("Can't obtain the determinant of a non_square matrix");
  183.  
  184.   if( row_lwb != col_lwb )
  185.     info(), _error("Row and col lower bounds are inconsistent");
  186.  
  187.   MatrixPivoting mp(*this);
  188.  
  189.   register double det = 1;
  190.   register int k;
  191.  
  192.   for(k=0; k<ncols && det != 0; k++)
  193.     det *= mp.pivoting_and_elimination();
  194.  
  195.   return det;
  196. }
  197.  
  198.